package org.artifact.core.plugin.storage;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.artifact.core.constant.ArtifactAttrConstant;
import org.artifact.core.db.AbstractDao;
import org.artifact.core.lang.AbstractPlugin;
import org.artifact.core.plugin.ioc.IocPlugin;
import org.artifact.core.server.ServerConfig;
import org.artifact.core.server.ServerContext;
import org.artifact.core.server.ServerPlugins;

import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 数据库落地插件
 *
 * @author apple
 */
public class StoragePlugin extends AbstractPlugin {

    static final Log log = LogFactory.get(StoragePlugin.class);

    private Set<AbstractDao<?>> daos = new HashSet<>();

    private StoragePluginConfig config;

    private String dataPath;

    private Runnable finishAllEvent;

    public StoragePlugin(Runnable finishAllEvent) {
        Map storage = ServerConfig.me().deepGet("plugins.storage");
        this.config = BeanUtil.mapToBean(storage, StoragePluginConfig.class, false);
        this.finishAllEvent = finishAllEvent;
    }

    public StoragePlugin(StoragePluginConfig config) {
        this.config = config;
    }

    @Override
    public boolean start() {
        try {
            // 扫描包
            scanPackage();
            // 检查表
            existsTable();
            // 开启定时
            CronUtil.schedule(config.getCrontab(), new Task() {
                @Override
                public void execute() {
                    finishAll();
                }
            });

            // 支持秒级别定时任务
//			CronUtil.setMatchSecond(true);
            CronUtil.start();


            return true;
        } catch (Exception e) {
            log.error(e);
        }
        return false;
    }

    @Override
    public boolean stop() {
        // 停止定时
        CronUtil.stop();

        for (AbstractDao<?> abstractDao : daos) {
            abstractDao.shutdown();
            abstractDao.backUp(null);
        }
        return true;
    }

    /**
     * 检查表
     */
    private void existsTable() {
        log.info("-> existsTable");
        for (AbstractDao<?> abstractDao : daos) {
            if (!abstractDao.existsTable()) {
                abstractDao.createTable();
            }
            abstractDao.restore(null);
        }
    }


    public void finishAll() {
        TimeInterval timer = DateUtil.timer();
        for (AbstractDao<?> abstractDao : daos) {
            abstractDao.finishAll();
        }
        // 设置最后写入时间
        ServerContext.me().getAttribute().put(ArtifactAttrConstant.LAST_STORAGE_DATE, new Date());
        if (finishAllEvent != null) {
            finishAllEvent.run();
        }
        log.debug("finishAll {}", timer.interval());
    }

    /**
     * 扫描DAO
     */
    private void scanPackage() {
        String scanPackage = config.getScanPackage();
        if (StrUtil.isEmpty(scanPackage)) {
            scanPackage = ServerContext.me().rootPackage();
        }
        Set<Class<?>> clazzs = ClassUtil.scanPackageBySuper(scanPackage, AbstractDao.class);
        for (Class<?> clazz : clazzs) {
            if (ClassUtil.isNormalClass(clazz)) {
                AbstractDao<?> abstractDao = (AbstractDao<?>) ServerPlugins.me().getPlugin(IocPlugin.class).getService(clazz);
                daos.add(abstractDao);
            }
        }
    }
}
